package userimpl

import (
	"context"
	"crypto/subtle"
	"gitee.com/go-caipu-team/go-caipu-plugin-sdk/pkg/utils"
	"go-caipu/pkg/setting"
	"time"

	"gorm.io/gorm"

	"go-caipu/pkg/infra/remotecache"
	"go-caipu/pkg/services/admin/model"
	"go-caipu/pkg/services/admin/role"
	user "go-caipu/pkg/services/admin/sysuser"
	"go-caipu/pkg/util"
)

type Service struct {
	store      store
	cache      *remotecache.Cache
	role       role.Service
	cfg        *setting.Cfg
	encryption *utils.SensitiveUtils
}

const (
	UserCacheKey = "admin_user_"
)

func ProvideService(db *gorm.DB, cache *remotecache.Cache, role role.Service, cfg *setting.Cfg) (*Service, error) {
	store := ProvideStore(db)
	s := &Service{
		store: &store,
		cache: cache,
		role:  role,
		cfg:   cfg,
	}
	s.encryption = utils.New(cfg.Application.EncryptionKey)
	return s, nil
}

func (s Service) GetUserPage(ctx context.Context, req user.GetUserPageCommand) ([]user.User, int64, error) {
	result, count, err := s.store.GetUserPage(ctx, req)
	if err != nil {
		return nil, 0, err
	}
	var items = make([]user.User, 0)
	for _, item := range result {
		dto := s.generateDto(item)
		//在列表对用户手册、邮箱脱敏
		dto.Phone = s.encryption.DesensitizePhone(dto.Phone)
		dto.Email, _ = s.encryption.DesensitizeEmail(dto.Email)
		items = append(items, dto)
	}
	return items, count, nil
}
func (s Service) GetUserByWhere(ctx context.Context, cmd user.GetUserRequest) ([]user.WorkUserInfo, error) {
	result, err := s.store.GetUserByWhere(ctx, cmd)
	if err != nil {
		return nil, err
	}
	items := make([]user.WorkUserInfo, len(result))
	for i := 0; i < len(result); i++ {
		items[i].ID = result[i].UserId
		items[i].Name = result[i].NickName
		items[i].Avatar = result[i].Avatar
		items[i].DeptId = int64(result[i].DeptId)
	}
	return items, nil
}
func (s Service) generateDto(u model.SysUser) user.User {
	result := user.User{
		UserId:           u.UserId,
		Username:         u.Username,
		NickName:         u.NickName,
		Sex:              u.Sex,
		PostId:           u.PostId,
		Remark:           u.Remark,
		Avatar:           u.Avatar,
		Status:           u.Status,
		RoleIds:          u.RoleIds,
		CreatedAt:        u.CreatedAt.Format("2006-01-02 15:04:05"),
		UpdatedAt:        u.UpdatedAt.Format("2006-01-02 15:04:05"),
		CreateUserString: u.CreateUser.NickName,
		UpdateUserString: u.UpdateUser.NickName,
	}
	//密码解密
	result.Phone, _ = s.encryption.Decrypt(u.Phone)
	result.Email, _ = s.encryption.Decrypt(u.Email)
	//获取操作用户
	if u.Dept != nil {
		result.DeptId = u.DeptId
		result.DeptName = u.Dept.DeptName
	}
	if len(u.Roles) > 0 {
		result.RoleIds = make([]string, len(u.Roles))
		result.RoleNames = make([]string, len(u.Roles))
		for j, role := range u.Roles {
			result.RoleIds[j] = util.Int64ToString(role.RoleId)
			result.RoleNames[j] = role.RoleName
		}
	}
	return result
}

func (s Service) GetUser(ctx context.Context, cmd user.GetUserCommand) (user.User, error) {
	cacheUser, exists := s.cache.Get(UserCacheKey + util.Int64ToString(cmd.UserId))
	if !exists {
		item, err := s.store.Get(ctx, cmd)
		if err != nil {
			return user.User{}, err
		}
		result := s.generateDto(item)
		s.cache.Set(UserCacheKey+util.Int64ToString(cmd.UserId), result, 0)
		return result, err
	}
	return cacheUser.(user.User), nil
}

func (s Service) Create(ctx context.Context, req user.InsertUserCommand) error {
	usr := model.SysUser{
		UserId:   req.UserId,
		Username: req.Username,
		NickName: req.NickName,
		//Phone:    req.Phone,
		//Email:    req.Email,
		RoleIds: req.RoleIds,
		Avatar:  req.Avatar,
		Sex:     req.Sex,
		DeptId:  req.DeptId,
		PostId:  req.PostId,
		Remark:  req.Remark,
		Status:  req.Status,
	}
	usr.Phone, _ = s.encryption.Encrypt(req.Phone)
	usr.Email, _ = s.encryption.Encrypt(req.Email)
	usr.CreateBy = req.CreateBy
	usr.CreatedAt = time.Now()
	usr.UpdatedAt = time.Now()

	salt, err := util.GetRandomString(10)
	if err != nil {
		return err
	}
	usr.Salt = salt
	if len(req.Password) > 0 {
		encodedPassword, err := util.EncodePassword(req.Password, salt)
		if err != nil {
			return err
		}
		usr.Password = encodedPassword
	}
	err2 := s.store.Create(ctx, usr)
	if err2 != nil {
		return err2
	}

	//绑定第三方值
	if req.ThirdUser != (user.UserThirdReq{}) {
		s.store.UserThirdBind(ctx, req.ThirdUser)
	}
	return nil
}

func (s Service) Update(ctx context.Context, cmd user.UpdateUserCommand) (err error) {
	UpdateCmd, err := s.store.Get(ctx, user.GetUserCommand{UserId: cmd.UserId})
	if err != nil {
		return err
	}
	UpdateCmd.NickName = cmd.NickName
	UpdateCmd.Phone = cmd.Phone
	UpdateCmd.RoleIds = cmd.RoleIds
	UpdateCmd.Avatar = cmd.Avatar
	UpdateCmd.Sex = cmd.Sex
	UpdateCmd.Email = cmd.Email
	UpdateCmd.DeptId = cmd.DeptId
	UpdateCmd.PostId = cmd.PostId
	UpdateCmd.Remark = cmd.Remark
	UpdateCmd.Status = cmd.Status
	UpdateCmd.UpdatedAt = time.Now()

	UpdateCmd.Phone, _ = s.encryption.Encrypt(cmd.Phone)
	UpdateCmd.Email, _ = s.encryption.Encrypt(cmd.Email)

	err = s.store.Update(ctx, UpdateCmd)
	s.cache.Delete([]string{UserCacheKey + util.Int64ToString(cmd.UserId)}, "")
	return err
}

func (s Service) UpdateAvatar(ctx context.Context, cmd user.UpdateUserAvatarReq) error {
	return s.store.UpdateAvatar(ctx, cmd)
}

func (s Service) UpdateStatus() error {
	//TODO implement me
	panic("implement me")
}

func (s Service) UpdateUserPwd(ctx context.Context, cmd user.UpdatePwdCommand) error {
	if err := validatePasswordSet(cmd.OldPassword); err != nil {
		return err
	}
	user, err2 := s.store.Get(ctx, user.GetUserCommand{UserId: cmd.UserId})

	if err2 != nil {
		return err2
	}
	if err := validatePassword(cmd.OldPassword, user.Password, user.Salt); err != nil {
		return err
	}
	//密码加密
	salt, err := util.GetRandomString(10)
	if err != nil {
		return err
	}
	cmd.Salt = salt
	if len(user.Password) > 0 {
		encodedPassword, err := util.EncodePassword(cmd.NewPassword, salt)
		if err != nil {
			return err
		}
		cmd.NewPassword = encodedPassword
	}
	return s.store.UpdateUserPwd(ctx, cmd)
}

// validatePasswordSet 验证密码是否为
func validatePasswordSet(password string) error {
	if len(password) == 0 {
		return user.ErrPasswordEmpty
	}

	return nil
}

// validatePassword 验证密码是否正角
var validatePassword = func(providedPassword string, userPassword string, userSalt string) error {
	passwordHashed, err := util.EncodePassword(providedPassword, userSalt)
	if err != nil {
		return err
	}
	if subtle.ConstantTimeCompare([]byte(passwordHashed), []byte(userPassword)) != 1 {
		return user.ErrInvalidCredentials
	}
	return nil
}

func (s Service) Remove(ctx context.Context, cmd user.RemoveUserCommand) error {

	return s.store.Remove(ctx, cmd)
}

func (s Service) ResetUpdatePwd(ctx context.Context, cmd user.ResetPasswordCommand) error {
	salt, err := util.GetRandomString(10)
	if err != nil {
		return err
	}
	var updateCmd = user.UpdatePwdCommand{
		UserId: cmd.UserId,
		Salt:   salt,
	}
	cmd.Salt = salt
	if len(cmd.Password) > 0 {
		encodedPassword, err := util.EncodePassword(cmd.Password, salt)
		if err != nil {
			return err
		}
		updateCmd.NewPassword = encodedPassword
	}
	return s.store.UpdateUserPwd(ctx, updateCmd)
}

func (s Service) GetProfile() error {
	//TODO implement me
	panic("implement me")
}

func (s Service) GetUserByUserName(ctx context.Context, username string) (user user.User, err error) {
	var sysUser model.SysUser
	sysUser, err = s.store.GetUserByUserName(ctx, username)
	if err != nil {
		return user, err
	}

	sysUser.GenerateDto(&user)
	return user, nil
}
func (s Service) AuthCheckRole(ctx context.Context, userId int64, method, path string) (bool, error) {
	cmd := user.GetUserCommand{UserId: userId}
	user, err := s.store.Get(ctx, cmd)
	if err != nil {
		return false, err
	}
	if user.Username == "admin" {
		return true, nil
	}
	if len(user.RoleIds) == 0 {
		return false, nil
	}

	req := make([][]interface{}, len(user.Roles))
	for i, item := range user.RoleIds {
		req[i] = []interface{}{item, path, method}
	}

	if result, err := s.role.BatchCheckEnforce(req); err == nil {
		for _, item := range result {
			if item {
				return true, nil
			}
		}
		return false, nil
	}
	return false, err
}

/**
 * UpdateUserRole 更新用户角色
 * @param ctx 上下文对象
 * @param cmd 修改用户角色实例
 * @return 是否更新成功，返回错误信息
 */
func (s Service) UpdateUserRole(ctx context.Context, cmd user.UpdateUserRole) error {
	return s.store.UpdateUserRole(ctx, cmd)
}

func (s Service) RefreshUserInfo(ctx context.Context, userId int64) error {
	return s.cache.Delete([]string{util.Int64ToString(userId)}, UserCacheKey)
}

func (s Service) UpdateUserBasicInfo(ctx context.Context, cmd user.UpdateUserBasicInfoReq) error {
	err := s.store.UpdateUserBasicInfo(ctx, cmd)
	s.cache.Delete([]string{UserCacheKey + util.Int64ToString(cmd.UserId)}, "")
	return err
}

// UserThird 第三方登录
func (s Service) UserThird(ctx context.Context, cmd user.UserThirdReq) (int64, bool, error) {
	return s.store.UserThird(ctx, cmd)
}

// UserThirdBind 第三方用户绑定
func (s Service) UserThirdBind(ctx context.Context, cmd user.UserThirdReq) error {
	//不存在则插入
	return s.store.UserThirdBind(ctx, cmd)
}

// UserThirdUnBind 第三方用户解绑
func (s Service) UserThirdUnBind(ctx context.Context, cmd user.UserThirdReq) error {
	//删除
	return s.store.UserThirdUnBind(ctx, cmd)
}
func (s Service) GetUserThird(ctx context.Context, userId int64) ([]string, error) {
	return s.store.GetUserThird(ctx, userId)
}
